/*这段代码实现了父子进程之间通过共享内存进行通信，并利用信号量实现进程间的同步。具体流程如下：

程序首先创建两个信号量sem_1和sem_2，并使用create_sem函数为它们生成唯一的键值，然后使用init_sem函数对它们进行初始化，sem_1的初始值为0，sem_2的初始值为1。

使用shmget函数创建一个共享内存段，指定大小为SIZE，权限为0666，并获取对应的共享内存标识符shmid。然后输出创建的共享内存标识符。

使用fork函数创建子进程。如果fork返回值小于0，则表示创建子进程失败，程序输出错误信息并退出。

子进程执行以下操作：

输出"In child process:"的提示信息。
执行sem_p(sem_1)操作，减少sem_1的值，进入等待状态，直到父进程执行sem_v(sem_1)操作增加sem_1的值。
使用shmat函数将共享内存段附加到子进程的地址空间，并将返回的共享内存地址赋给shm_addr。
将共享内存中的数据拷贝到缓冲区buff中，并输出接收到的数据。
使用shmdt函数将共享内存从子进程的地址空间分离。
执行sem_v(sem_2)操作，增加sem_2的值，唤醒父进程。
父进程执行以下操作：

输出"In parent process:"的提示信息。
执行sem_p(sem_2)操作，减少sem_2的值，进入等待状态，直到子进程执行sem_v(sem_2)操作增加sem_2的值。
使用shmat函数将共享内存段附加到父进程的地址空间，并将返回的共享内存地址赋给shm_addr。
提示用户输入消息，并将用户输入的消息拷贝到共享内存中。
使用shmdt函数将共享内存从父进程的地址空间分离。
执行sem_v(sem_1)操作，增加sem_1的值，唤醒子进程。
等待子进程结束。
使用shmctl函数删除共享内存段。
使用del_sem函数删除信号量sem_1和sem_2。
最后，父进程退出。

通过共享内存和信号量的结合，父子进程可以实现双向的通信和同步，确保数据在两个进程之间正确地传递和处理*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "sem_com.c"

#define SIZE 2048

int main(){
    pid_t pid;
    int shmid;
    char *shm_addr;
    int sem_1,sem_2;
    char buff[SIZE];

    // 创建信号量sem_1和sem_2，并初始化它们的初始值
    sem_1 = create_sem('a');
    sem_2 = create_sem('b');
    init_sem(sem_1, 0);
    init_sem(sem_2, 1);   

    // 创建共享内存段，指定大小为SIZE，权限为0666，并获取共享内存标识符shmid
    shmid = shmget(IPC_PRIVATE, SIZE, 0666);
    printf("Create shared memory: %d.\n", shmid);

    if ((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if (pid == 0){
        printf("In child process:\n");

        // 子进程执行P操作，减少sem_1的值，进入等待状态
        sem_p(sem_1);
        shm_addr = shmat(shmid, 0, 0);
        
        // 将共享内存中的数据拷贝到缓冲区buff中
        strcpy(buff, shm_addr);
        printf("Child receive:%s\n", buff);

        shmdt(shm_addr);

        // 子进程执行V操作，增加sem_2的值，唤醒父进程
        sem_v(sem_2);

        exit(0);
    }else{
        printf("In parent process:\n");
        
        // 父进程执行P操作，减少sem_2的值，进入等待状态
        sem_p(sem_2);
        shm_addr = shmat(shmid, 0, 0);

        printf("\nInput msg:\n");
        fgets(buff, SIZE, stdin);

        // 将用户输入的消息拷贝到共享内存中
        strncpy(shm_addr, buff, strlen(buff));

        shmdt(shm_addr);

        // 父进程执行V操作，增加sem_1的值，唤醒子进程
        sem_v(sem_1);

        // 等待子进程结束
        waitpid(pid, NULL, 0);
        
        // 删除共享内存段
        shmctl(shmid, IPC_RMID, NULL);

        // 删除信号量sem_1和sem_2
        del_sem(sem_1);
        del_sem(sem_2);

        exit(0);
    }

    return 0;
}
